# -*-coding:utf-8-*-

import json
import time
from pyrestful import mediatypes
from pyrestful.rest import get, post, put, delete
from handlers.base import PayBaseHandler
from utils.auth import authenticated
from utils.http import http_post
import base64
import binascii
from Crypto import Random
from Crypto.Hash import SHA
from Crypto.Cipher import DES
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
from Crypto.PublicKey import RSA
import urlparse
import urllib
from tornado.httpclient import AsyncHTTPClient, HTTPRequest, HTTPClient
from tornado.gen import coroutine, Return
from utils.misc import dict_from_xml, dict_to_xml
from bson.objectid import ObjectId

# from tornado.web import asynchronous

ALLINPAY_API_PREFIX = 'https://www.allinpaycard.com/asaop/rest/api'

'''
ECB模式：电子密本方式，这是JAVA封装的DES算法的默认模式，就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文，
最后一段不足8个字节，则补足8个字节（注意：这里就涉及到数据补位了）进行计算，之后按照顺序将计算所得的数据连在一起即可，各段数据之间互不影响。

数据补位一般有NoPadding和PKCS7Padding(JAVA中是PKCS5Padding)填充方式，PKCS7Padding和PKCS5Padding实际只是协议不一样，
根据相关资料说明：PKCS5Padding明确定义了加密块是8字节，PKCS7Padding加密快可以是1-255之间。但是封装的DES算法默认都是8字节，所以可以认为他们一样。
数据补位实际是在数据不满8字节的倍数，才补充到8字节的倍数的填充过程。

NoPadding填充方式：算法本身不填充，比如.NET的padding提供了有None，Zeros方式，分别为不填充和填充0的方式。

PKCS7Padding（PKCS5Padding）填充方式：为.NET和JAVA的默认填充方式，对加密数据字节长度对8取余为r，如r大于0，则补8-r个字节，字节为8-r的值；如果r等于0，则补8个字节8。比如：
加密字符串为为AAA，则补位为AAA55555;加密字符串为BBBBBB，则补位为BBBBBB22；加密字符串为CCCCCCCC，则补位为CCCCCCCC88888888。

关键数据密钥: a32df3e4
私钥证书密钥: 123456(?何用)

关键字加密示例：
明文：关键信息加密测试abc123
密文：RtLrkCgLYiPmIteDj0WtQROdU39A/Uo8TkQxXOSer7U=

加密签名示例：
明文：amount4999app_keytesthnchannel0comment测试description签名测试formatjsonmer_id999290053990002methodallinpay.order.orderinstall.addnotify_urlhttps://www.baidu.comorder_id201706301128473422pdno0200return_urlhttps://www.baidu.comsign_v1timestamp20170703093953trade_date20170703trade_time093953v1.0
密文：3bc2e6afad5d0a428a98a43cabaddb0f45400b75dfed03aefd2fa49350d391aae4b378cc989901f6c3d1c11bd116fec0044390370f5aedc3c678ce12713234f90a6914094adf594a6a2d45707c24b138b424caa8b0ad818de9a7136190cffc966002158003194c071c40449034f4c5f0a5fcfea21f93489b5bdbdf47916e2632


生产环境接入地址：https://www.allinpaycard.com/asaop/rest/api/

广东东臣科技实业有限公司
商户简称：东臣科技
mer_id: 999603050650001
app_key: dckj
关键数据密码: cfRy6J9Z
私钥密码: gKP4e7f0ZUkZt7xyJ8ZCIfgsBpBO9Nvy


生产企业管理台
http://www.ulinkpay.com/
用户名：营业执照号
密码：营业执照号后六位
登陆后请修改密码

text:
amount2300app_keydckjchannel1formatjsonmer_id999603050650001methodallinpay.order.orderinstall.addnotify_urlhttp://wx.iot.microembed.net/api/orders/transfers/allinpay/on_notifynper6order_idtransferspdno0200sign_v1timestamp20171122194759trade_date20171122trade_time194759v1.0
sign:(len = 512, 生产, 测试的话 len = 256)
3291d84f5e88d39b391a5deac947105512eefbdb3e5ca39d15eed882e0fe9d4f034003219a02e1768e3216578eea03ee54a6578849f844e7db7df15390ee84feddad92d57d01827f7c6ac2525961401e1b277a15daed33646c1ef70f6f5a0ee9a824dec1f30c340f06789b2cd81b5e23d9b2d258791ff2fbfdb24b88b1501fb856d199dce3e8fe9de1e52985aca51a7429c417c18b77facf911b38a3c890d8f65757e2c15c15b68511492c03440ddcaa747f1fdc24dd213099491ede4c6b46da9d04c7a9621b8eead0bad6ea2cc0062ca2d1dc6c05b2742ab043be7c1e49d383877e31b6bc4eb4b93c6f0492c66f76b9a1f5bcb7c71bcde9982ebb9914b35073

通联转帐信息
4. 商户号: 200603000001374
5. 用户名: 20060300000137404
6. 用户密码: 111111
7. 私钥密码: 111111
'''


def des_encrypt(text):
    padding_len = 8 - len(text) % 8
    padding = ('%c' % padding_len) * padding_len
    cipher = DES.new('a32df3e4', DES.MODE_ECB)
    return base64.urlsafe_b64encode(cipher.encrypt(text + padding))
    # return base64.b64encode(cipher.encrypt(text + padding))


def des_decrypt(text):
    cipher = DES.new('a32df3e4', DES.MODE_ECB)
    print cipher.decrypt(base64.urlsafe_b64decode(text))


def rsa_sign(message):
    with open('private.pem') as f:
        key = f.read()
        rsakey = RSA.importKey(key)
        signer = Signature_pkcs1_v1_5.new(rsakey)
        digest = SHA.new()
        digest.update(message)
        sign = signer.sign(digest)
        signature = binascii.hexlify(sign)
        print signature
    with open('public.pem') as f:
        key = f.read()
        rsakey = RSA.importKey(key)
        verifier = Signature_pkcs1_v1_5.new(rsakey)
        digest = SHA.new()
        # Assumes the data is base64 encoded to begin with
        digest.update(message)
        is_verify = verifier.verify(digest, binascii.a2b_hex(signature))
        print is_verify
    return signature


class AllinpayHandler(PayBaseHandler):
    def __init__(self, application, request, **kwargs):
        super(AllinpayHandler, self).__init__(application, request, **kwargs)

    def rsa_sign(self, message):
        with open(self.app.get_allinpay_rsa_pri_key()) as f:
            key = f.read()
            rsakey = RSA.importKey(key)
            signer = Signature_pkcs1_v1_5.new(rsakey)
            digest = SHA.new()
            digest.update(message)
            sign = signer.sign(digest)
            signature = binascii.hexlify(sign)
            return signature

    def rsa_verify(self, message, signature):
        with open(self.app.get_allinpay_rsa_pub_key()) as f:
            key = f.read()
            rsakey = RSA.importKey(key)
            verifier = Signature_pkcs1_v1_5.new(rsakey)
            digest = SHA.new()
            digest.update(message)
            if not verifier.verify(digest, binascii.a2b_hex(signature)):
                raise Exception('signature verify fail')

    def sign_arguments(self, arguments, sign_field_name='sign', sign_key=None):
        message = self.message_for_sign_from_arguments(arguments)
        sign = self.rsa_sign(message)
        arguments['sign'] = sign

    def message_for_sign_from_arguments(self, arguments):
        keys = arguments.keys()
        keys.sort()
        message = ''
        for key in keys:
            if 'sign' != key:
                message += '%s%s' % (key, str(arguments[key]))
        return message

    @coroutine
    def allinpay_http_post(self, url, arguments, **kwargs):
        self.logger.info(json.dumps(arguments))
        arguments = urllib.urlencode(arguments)
        response = yield http_post(url, arguments, dump_body=False, **kwargs)
        self.logger.info(response.body)
        response = json.loads(response.body)
        raise Return(response)

    '''
    示例:
    msg=消费成功&nper=12&orderId=25719056950757307990&result=1&sign=55a852a6583a753f4e052af5cb123bc76566d54b8d27b7e1451423fefa5f554d6a9cc97a682718f90251c214d472d0cab8e8dda1465e01e61c3245cf1560fec1ee7424a007e100ebedc1d978577ef28621c1e50c3abc5faa3ec22ead09c111661c408bbeea08a517c19492674a854d614a577bc7f2d1bcbe136202e0212b9ffb0b8b9a7514b5feef3ceb5ae395cbbb82bfba9cf506a065939017fa4b11e6a67db7803a87d63f769971d937ee4fa8c27cf4c44d2ad6703a3e583515a0e9d5b818db86d01b8aefc356f3244c7b3bc9a2ade080abaf9bc6d62b9eb113ded9723408f3556ca2e99d512924f225ccc4e49c8eb7419afb74007dd778e71d0f48e0&totalAmt=1999.00&
    {
        'orderId': '25719056950757307990',
        'totalAmt': '1999.00',
        'sign': '55a852a6583a753f4e052af5cb123bc76566d54b8d27b7e1451423fefa5f554d6a9cc97a682718f90251c214d472d0cab8e8dda1465e01e61c3245cf1560fec1ee7424a007e100ebedc1d978577ef28621c1e50c3abc5faa3ec22ead09c111661c408bbeea08a517c19492674a854d614a577bc7f2d1bcbe136202e0212b9ffb0b8b9a7514b5feef3ceb5ae395cbbb82bfba9cf506a065939017fa4b11e6a67db7803a87d63f769971d937ee4fa8c27cf4c44d2ad6703a3e583515a0e9d5b818db86d01b8aefc356f3244c7b3bc9a2ade080abaf9bc6d62b9eb113ded9723408f3556ca2e99d512924f225ccc4e49c8eb7419afb74007dd778e71d0f48e0',
        'result': '1',
        'nper': '12',
        'msg': '\xe6\xb6\x88\xe8\xb4\xb9\xe6\x88\x90\xe5\x8a\x9f'
    }

    msg=该笔订单失效&orderId=14176350392678757726&result=3&sign=5f4835c8830036e1e22df6384c7c2ec1fe4207bbee26449fb245e5d1da936fa16054e295978bbb1f78556785fee7aed9d5849f51f1f18c1c55ede7a6aa6ada64ca7ecbb87fc2d3100838732f6d8dfa0464be62ee08658f20732af180fcd344678c2453a10039648131583e7284f81ece42264b1277f4a7338216ef42037b347908ac0aa919834aa67c41de9d0d72879ffb09625d23f5d6f357d908530ce36fc980707f8a5518ca87add10cc77dee0cedbf1d7cab7c9642991047bab629689d6c3726d83c73d07d436804c17684de7e5b452e02bf1f6db099ae0252340d1913a7e417ee1d497a3a461ab0141bb7885d95fc8065ac6dc964a5c2a4043259&

    msg=消费成功
    nper=12
    orderId=201608301002296995
    result=1
    totalAmt=766.00
    sign=3e3827...

    msg=订单消费失败
    nper=12
    orderId=20170607115145
    result=2
    totalAmt=766.01
    sign= 884ab1...

    msg=该笔订单失效
    orderId=20170707129496715343
    result=3
    sign= 6f8684...
    '''

    @post(_path='/api/orders/{oid}/allinpay/on_notify', _types=[str])
    @coroutine
    def allinpay_on_notify(self, oid):
        self.logger.info(self.request.body)
        order = yield self.orders_dao.get_record_by_id(oid)
        if order is None:
            raise Exception('invalid order id')
        # NOTE: the following 4 lines for self.rsa_verify
        # uid = order.uid
        # user = yield self.users_dao.get_user_by_id(None, uid)
        # aid = user.app_id
        # self.app = self.apps_dao.get_app_by_id(aid)
        self.logger.info(order.status)
        arguments = {}
        for key, value in self.request.body_arguments.iteritems():
            arguments[key] = value[len(value) - 1]
        # from urlparse import parse_qsl
        # arguments = dict(parse_qsl(self.request.body))
        if 'to_be_paid' == order.status:
            message = self.message_for_sign_from_arguments(arguments)
            self.logger.info(message)
            # NOTE: tmp comment
            # self.rsa_verify(message, arguments['sign'])
            if arguments['result'] == '1' and float(arguments['totalAmt']) == order.get_total_price():
                pay_info = {
                    'allinpay': arguments,
                }
                yield self.set_order_paid(order, paid_by='allinpay', pay_info=pay_info)
            else:
                self.logger.error('check response fail:\n%s' % self.request.body)
        self.finish('success')

    def build_common_arguments(self, order_no, method):
        arguments = {
            'app_key': self.app.get_allinpay_app_key(),
            'mer_id': self.app.get_allinpay_mer_id(),

            'method': method,
            'timestamp': time.strftime('%Y%m%d%H%M%S'),
            'v': '1.0',
            'sign_v': '1',
            'format': 'json',
            'order_id': str(order_no),  # <len: 12-20>,
        }
        return arguments

    @get(_path='/api/orders/{oid}/allinpay/prepay', types=[str])
    @authenticated
    @coroutine
    def get_allinpay_prepay(self, oid):
        order = yield self.orders_dao.get_record_by_id(oid)
        if order is None:
            raise Exception('invalid order id')
        if 'to_be_paid' != order.status:
            raise Exception('order is paid')
        order_no = yield self.orders_dao.update_order_no(self.user_id, oid)
        arguments = self.build_common_arguments(order_no, 'allinpay.order.orderinstall.add')
        notify_url = '%s://%s/api/orders/%s/allinpay/on_notify' % (self.request.protocol, self.request.host, oid)
        extra_arguments = {
            'channel': '1',  # 0: pc, 1: wpa,
            'amount': '%.2f' % order.get_total_price(),  # 600-20000
            # 'amount': '600',
            'trade_date': time.strftime('%Y%m%d'),
            'trade_time': time.strftime('%H%M%S'),
            'nper': '12',  # 6 | 12 | 24,
            'pdno': '0200',
            # 'unalter': 'nper',  # 'nper,creditName'
            'notify_url': notify_url,
        }
        arguments = dict(arguments, **extra_arguments)
        self.sign_arguments(arguments)
        self.respond_success(arguments)

    '''
    {
        "order_info_response": {
            "res_timestamp": 20161202110225,
            "res_sign": "64328AA7A4242690BD73E72C88B99CE2BE6549EB1800AFC6E49931C39
    471CC90FC93A4DB7D26006FC004496ACE82CC74B920DAE13149319889C3DDDC9F8CF65B4EB31DCA94E4FC92AC022480350FCF7A2E32E70CD3E221D47A7359528EA1D6590EDBE96FAC6CB99C3761A4E7D6FF8C0F1807E5AE0D84BEB6104ACD60F4AACB09",
            "map": {
                "entry": {
                    "key": 201609271648581380,
                    "value": 3
                }
            }
        }
    }
    其中KEY为支付流水号，value为订单状态：
    0: 待支付
    1: 支付成功
    2: 支付失败
    3: 订单失效
    4: 退货待审批
    5: 退货成功
    111: 支付流水号为空，查无此项

    '''

    @get(_path='/api/orders/{oid}/allinpay/status', _types=[str])
    @authenticated
    @coroutine
    def get_allinpay_status(self, oid):
        order = yield self.orders_dao.get_record_by_id(oid)
        if order is None:
            raise Exception('invalid order id')
        status = order.status
        if 'to_be_paid' == status:
            arguments = self.build_common_arguments(order.order_no, 'allinpay.order.orderinstall.query')
            self.sign_arguments(arguments)
            response = yield self.allinpay_http_post(ALLINPAY_API_PREFIX, arguments)
            if 1 == response['order_info_response']['map']['entry']['value']:
                yield self.set_order_paid(order, paid_by='allinpay')
                status = 'paid'
        self.respond_success({'status': status})

    '''
    订单退货
    {
        "sucess_business_response": {
            "res_timestamp": 20170106154047,
            "res_sign": "14DCB4421911131D51E529BBE98950454BC857733F51175AEB7F756BBFBDA58490C7468DAFC94A456CC03E1B75A621F320BD8053573A5AAF6E38BF172F61B64CB37DABD83B563DEA258D73F73AF615C16B4A3001281DCC2A3C2D15CDEAD57D26A79514962C5FC3B55888A197EE36E2C40AF4CC479233BE2D4B80FB7E912FB042",
            "code": 0,
            "msg": "退货申请提交成功"
        }
    }

    method: allinpay.order.orderinstall.refund
    '''

    '''
    <?xml version="1.0" encoding="GBK"?>
    <AIPG>
      <INFO>
        <TRX_CODE>100014</TRX_CODE>
        <VERSION>03</VERSION>
        <DATA_TYPE>2</DATA_TYPE>
        <LEVEL>5</LEVEL>
        <MERCHANT_ID>200581000000519</MERCHANT_ID>
        <USER_NAME>20058100000051902</USER_NAME>
        <USER_PASS>111111</USER_PASS>
        <REQ_SN>1377051780610</REQ_SN>
        <SIGNED_MSG>4b560e777597045d7273e73865671f3af7a34db15a3000eb7f5247090137f8e1feec91977364b6716f7407a7e540a8664048029832c18fdfcb37086bd2462310644a8ba3f81ce2001959219e7564dbb83a15aeae579ac814853be5e6bac7047dd108dcd37790b4ea0956118924c3a08e9e72e0baacfc74ba0298ac627769c07f</SIGNED_MSG>
      </INFO>
      <TRANS>
        <BUSINESS_CODE>00600</BUSINESS_CODE>
        <MERCHANT_ID>200581000000519</MERCHANT_ID>
        <SUBMIT_TIME>20130821102300</SUBMIT_TIME>
        <BANK_CODE>0105</BANK_CODE>
        <ACCOUNT_NO>622588121251757643</ACCOUNT_NO>
        <ACCOUNT_NAME>测试试</ACCOUNT_NAME>
        <ACCOUNT_PROP>0</ACCOUNT_PROP>
        <AMOUNT>100000</AMOUNT>
        <CURRENCY>CNY</CURRENCY>
        <TEL>13434245846</TEL>
        <CUST_USERID>252523524253xx</CUST_USERID>
      </TRANS>
    </AIPG>
    '''

    @staticmethod
    def rsa_sign_for_transfer(app, message):
        with open(app.get_allinpay_transfer_rsa_pri_key()) as f:
            key = f.read()
            rsakey = RSA.importKey(key)
            signer = Signature_pkcs1_v1_5.new(rsakey)
            digest = SHA.new()
            digest.update(message)
            sign = signer.sign(digest)
            signature = binascii.hexlify(sign)
            return signature

    @staticmethod
    def rsa_verify_for_transfer(app, message, signature):
        with open(app.get_allinpay_transfer_rsa_pub_key()) as f:
            key = f.read()
            rsakey = RSA.importKey(key)
            verifier = Signature_pkcs1_v1_5.new(rsakey)
            digest = SHA.new()
            digest.update(message)
            if not verifier.verify(digest, binascii.a2b_hex(signature)):
                raise Exception('signature verify fail')

    @staticmethod
    @coroutine
    def allinpay_transfers(authenticated_handler, transfer):
        app = authenticated_handler.app
        logger = authenticated_handler.logger
        info = {
            'TRX_CODE': '100014',
            'VERSION': '03',
            'DATA_TYPE': '2',
            'LEVEL': '5',
            'MERCHANT_ID': app.get_allinpay_transfer_mer_id(),
            'USER_NAME': app.get_allinpay_transfer_username(),
            'USER_PASS': app.get_allinpay_transfer_password(),
            'REQ_SN': '%s_%s' % (app.get_allinpay_transfer_mer_id(), str(ObjectId())),
        }
        trans = {
            'BUSINESS_CODE': '09900',
            'MERCHANT_ID': app.get_allinpay_transfer_mer_id(),
            'SUBMIT_TIME': time.strftime('%Y%m%d%H%M%S'),  # YYYYMMDDHHMMSS
            'ACCOUNT_NO': transfer.allinpay_account_no,
            'ACCOUNT_NAME': transfer.allinpay_account_name,
            'ACCOUNT_PROP': '0',  # 0: 私人 1: 公司
            'AMOUNT': int(transfer.amount * 100),
        }
        aipg = {
            'INFO': info,
            'TRANS': trans,
        }
        x = dict_to_xml(aipg, encoding='utf-8', header=True, root_tag_name='AIPG')
        x = x.replace('<?xml version="1.0" encoding="utf-8"?>', '<?xml version="1.0" encoding="GBK"?>')
        x = x.decode('utf-8').encode('GBK')
        logger.info('text to sign: %s' % x)
        signature = AllinpayHandler.rsa_sign_for_transfer(app, x)
        logger.info('signature: %s' % signature)
        info.update(SIGNED_MSG=signature)
        x = dict_to_xml(aipg, encoding='utf-8', header=True, root_tag_name='AIPG')
        x = x.replace('<?xml version="1.0" encoding="utf-8"?>', '<?xml version="1.0" encoding="GBK"?>')
        x = x.decode('utf-8').encode('GBK')
        logger.info('signed request body: %s' % x)
        url = 'https://tlt.allinpay.com/aipg/ProcessServlet'
        response = yield http_post(url, x, dump_body=False)
        logger.info('response: %s' % str(response))
        x = response.body
        logger.info('response.body: %s' % x)

        # NOTE: verify signature fail
        # sign_tag_start = '<SIGNED_MSG>'
        # sign_tag_end = '</SIGNED_MSG>'
        # signature = x[x.find(sign_tag_start) + len(sign_tag_start):x.find(sign_tag_end)]
        # message = x.replace('    %s%s%s\n' % (sign_tag_start, signature, sign_tag_end), '')
        # logger.info('message: %s, signature: %s' % (message, signature))
        # AllinpayHandler.rsa_verify_for_transfer(app, message, signature)

        x = x.decode('GBK').encode('utf-8')
        x = x.replace('<?xml version="1.0" encoding="GBK"?>', '<?xml version="1.0" encoding="utf-8"?>')
        x = x.replace('\n', '')
        x = x.replace('  ', '')
        x = x.replace('  ', '')
        d = dict_from_xml(x)
        logger.info('response from transfer server: %s' % json.dumps(d))
        raise Return(d)


def test_transfer():
    from daos.apps import AppsDao
    import pymongo
    db = pymongo.MongoClient().get_database('bora')
    app_dao = AppsDao(db)
    app = app_dao.get_app('CF859FF521D73AA88EAD95197BC26420')


# if '__main__' == __name__:
def test():
    import base64
    import binascii
    from Crypto import Random
    from Crypto.Hash import SHA
    from Crypto.Cipher import DES
    from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
    from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
    from Crypto.PublicKey import RSA
    import urlparse
    import urllib
    s = 'msg=该笔订单失效&orderId=14176350392678757726&result=3&sign=5f4835c8830036e1e22df6384c7c2ec1fe4207bbee26449fb245e5d1da936fa16054e295978bbb1f78556785fee7aed9d5849f51f1f18c1c55ede7a6aa6ada64ca7ecbb87fc2d3100838732f6d8dfa0464be62ee08658f20732af180fcd344678c2453a10039648131583e7284f81ece42264b1277f4a7338216ef42037b347908ac0aa919834aa67c41de9d0d72879ffb09625d23f5d6f357d908530ce36fc980707f8a5518ca87add10cc77dee0cedbf1d7cab7c9642991047bab629689d6c3726d83c73d07d436804c17684de7e5b452e02bf1f6db099ae0252340d1913a7e417ee1d497a3a461ab0141bb7885d95fc8065ac6dc964a5c2a4043259&'
    s = 'msg=消费成功&nper=12&orderId=25719056950757307990&result=1&sign=55a852a6583a753f4e052af5cb123bc76566d54b8d27b7e1451423fefa5f554d6a9cc97a682718f90251c214d472d0cab8e8dda1465e01e61c3245cf1560fec1ee7424a007e100ebedc1d978577ef28621c1e50c3abc5faa3ec22ead09c111661c408bbeea08a517c19492674a854d614a577bc7f2d1bcbe136202e0212b9ffb0b8b9a7514b5feef3ceb5ae395cbbb82bfba9cf506a065939017fa4b11e6a67db7803a87d63f769971d937ee4fa8c27cf4c44d2ad6703a3e583515a0e9d5b818db86d01b8aefc356f3244c7b3bc9a2ade080abaf9bc6d62b9eb113ded9723408f3556ca2e99d512924f225ccc4e49c8eb7419afb74007dd778e71d0f48e0&totalAmt=1999.00&'
    d = dict(urlparse.parse_qsl(s))
    signature = d['sign']
    del d['sign']
    keys = d.keys()
    keys.sort()
    message = ''
    for key in keys:
        if 'sign' != key:
            message += '%s%s' % (key, str(d[key]))
    with open('public_srv.pem') as f:
        key = f.read()
        rsakey = RSA.importKey(key)
        verifier = Signature_pkcs1_v1_5.new(rsakey)
        digest = SHA.new()
        print message
        digest.update(message)
        if not verifier.verify(digest, binascii.a2b_hex(signature)):
            raise Exception('signature verify fail')

    '''
    curl -i -X POST -d 'msg=该笔订单失效&orderId=14176350392678757726&result=3&sign=5f4835c8830036e1e22df6384c7c2ec1fe4207bbee26449fb245e5d1da936fa16054e295978bbb1f78556785fee7aed9d5849f51f1f18c1c55ede7a6aa6ada64ca7ecbb87fc2d3100838732f6d8dfa0464be62ee08658f20732af180fcd344678c2453a10039648131583e7284f81ece42264b1277f4a7338216ef42037b347908ac0aa919834aa67c41de9d0d72879ffb09625d23f5d6f357d908530ce36fc980707f8a5518ca87add10cc77dee0cedbf1d7cab7c9642991047bab629689d6c3726d83c73d07d436804c17684de7e5b452e02bf1f6db099ae0252340d1913a7e417ee1d497a3a461ab0141bb7885d95fc8065ac6dc964a5c2a4043259&' http://wx.hifocus.top/api/orders/5a1ab1d997c2093cd968ca3b/allinpay/on_notify
    '''
